package com.danco.training.zaneuskaya.service.impl;

import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.Logger;
import org.hibernate.HibernateException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.danco.training.zaneuskaya.domain.Account;
import com.danco.training.zaneuskaya.domain.Education;
import com.danco.training.zaneuskaya.domain.Event;
import com.danco.training.zaneuskaya.domain.Forum;
import com.danco.training.zaneuskaya.domain.Interest;
import com.danco.training.zaneuskaya.domain.Job;
import com.danco.training.zaneuskaya.domain.Message;
import com.danco.training.zaneuskaya.domain.User;
import com.danco.training.zaneuskaya.repository.AccountDao;
import com.danco.training.zaneuskaya.repository.EducationDao;
import com.danco.training.zaneuskaya.repository.EventDao;
import com.danco.training.zaneuskaya.repository.ForumDao;
import com.danco.training.zaneuskaya.repository.InterestDao;
import com.danco.training.zaneuskaya.repository.JobDao;
import com.danco.training.zaneuskaya.repository.MessageDao;
import com.danco.training.zaneuskaya.repository.UserDao;
import com.danco.training.zaneuskaya.service.UserService;
import com.danco.training.zaneuskaya.service.exception.UserException;
/**
 * @author Zaneuskaya Aliaksandra
 *
 */
@Service("userService")
@Transactional
public class UserServiceImpl implements UserService {

	private static final String EDUCATION_NOT_FOUND = "Education not found";

	private static final String USER_IS_NULL = "User is null";

	private static final String JOB_NOT_FOUND = "Job not found";

	private static final String USER_HASN_T_INTEREST = "User hasn't interest";

	private static final String USER_ALREADY_HAS_INTEREST = "User already has interest";

	private static final String USER_HASN_T_THIS_JOB = "User hasn't this job";

	private static final String USER_ALREADY_HAS_THIS_JOB = "User already has this job";

	private static final String USER_HASN_T_THIS_EDUCATION = "User hasn't this education";

	private static final String USER_ALREADY_HAS_THIS_EDUCATION = "User already has this education";

	private static final String ALREADY_FRIENDS = "Already friends";

	private static final String USER_ALREADY_EXISTS_WITH_ACCOUNT = "User already exists with account ";

	private static final Logger logger = Logger
			.getLogger(UserServiceImpl.class);

	@Autowired
	private UserDao userDao;

	@Autowired
	private MessageDao messageDao;

	@Autowired
	private AccountDao accountDao;

	@Autowired
	private EventDao eventDao;

	@Autowired
	private ForumDao forumDao;

	@Autowired
	private EducationDao educationDao;

	@Autowired
	private JobDao jobDao;

	@Autowired
	private InterestDao interestDao;

	public InterestDao getInterestDao() {
		return interestDao;
	}

	public void setInterestDao(InterestDao interestDao) {
		this.interestDao = interestDao;
	}

	public JobDao getJobDao() {
		return jobDao;
	}

	public void setJobDao(JobDao jobDao) {
		this.jobDao = jobDao;
	}

	public EducationDao getEducationDao() {
		return educationDao;
	}

	public void setEducationDao(EducationDao educationDao) {
		this.educationDao = educationDao;
	}

	public ForumDao getForumDao() {
		return forumDao;
	}

	public void setForumDao(ForumDao forumDao) {
		this.forumDao = forumDao;
	}

	public MessageDao getMessageDao() {
		return messageDao;
	}

	public void setMessageDao(MessageDao messageDao) {
		this.messageDao = messageDao;
	}

	public UserDao getUserDao() {
		return userDao;
	}

	public void setUserDao(UserDao userDao) {
		this.userDao = userDao;
	}

	public AccountDao getAccountDao() {
		return accountDao;
	}

	public void setAccountDao(AccountDao accountDao) {
		this.accountDao = accountDao;
	}

	public EventDao getEventDao() {
		return eventDao;
	}

	public void setEventDao(EventDao eventDao) {
		this.eventDao = eventDao;
	}

	@Override
	public void createEntity(User t) throws UserException {
		try {
			if (userDao.findUserByAccount(t.getAccount()) == null) {
				userDao.create(t);
			} else {
				throw new UserException(USER_ALREADY_EXISTS_WITH_ACCOUNT
						+ t.getAccount().getAccountId());
			}
		} catch (NullPointerException e) {
			logger.error(e.getMessage(), e);
		} catch (HibernateException e) {
			logger.error(e.getMessage(), e);
		} 

	}

	@Override
	public void deleteEntityById(Integer id) {
		try {
			User user = userDao.read(id);
			if (user != null) {
				userDao.delete(user);
			}
		} catch (NullPointerException e) {
			logger.error(e.getMessage(), e);
		} catch (HibernateException e) {
			logger.error(e.getMessage(), e);
		}
	}

	@Override
	public void updateEntity(User t) {
		try {
			User user = userDao.read(t.getUserId());
			user.setAddress(t.getAddress());
			user.setBirthdayDate(t.getBirthdayDate());
			user.setEducations(t.getEducations());
			user.setEvents(t.getEvents());
			user.setFirstName(t.getFirstName());
			user.setLastName(t.getLastName());
			user.setPhone(t.getPhone());
			user.setForums(t.getForums());
			user.setFriendOf(t.getFriendOf());
			user.setFriends(t.getFriends());
			user.setGender(t.getGender());
			user.setInterests(t.getInterests());
			user.setJobs(t.getJobs());
			user.setMaritalState(t.getMaritalState());
			user.setOnline(t.isOnline());
			user.setStatus(t.getStatus());
			user.setUserCity(t.getUserCity());
			user.setUserCountry(t.getUserCountry());
			user.setWebSite(t.getWebSite());
		} catch (NullPointerException e) {
			logger.error(e.getMessage(), e);
		} catch (HibernateException e) {
			logger.error(e.getMessage(), e);
		}

	}

	@Override
	public User getEntityById(Integer id) {
		User user = null;
		try {
			user = userDao.read(id);
		} catch (NullPointerException e) {
			logger.error(e.getMessage(), e);
		} catch (HibernateException e) {
			logger.error(e.getMessage(), e);
		}
		return user;
	}

	@Override
	public List<User> getEntityList() {
		List<User> users = null;
		try {
			users = userDao.readAll();
		}

		catch (NullPointerException e) {
			logger.error(e.getMessage(), e);
		} catch (HibernateException e) {
			logger.error(e.getMessage(), e);
		}
		return users;
	}

	@Override
	public List<User> getOnlineUserList() {
		List<User> users = null;
		try {
			users = userDao.findOnlineUsers();
		} catch (NullPointerException e) {
			logger.error(e.getMessage(), e);
		} catch (HibernateException e) {
			logger.error(e.getMessage(), e);
		}
		return users;
	}

	@Override
	public List<User> getOfflineUserList() {
		List<User> users = null;
		try {
			users = userDao.findOfflineUsers();
		} catch (NullPointerException e) {
			logger.error(e.getMessage(), e);
		} catch (HibernateException e) {
			logger.error(e.getMessage(), e);
		}
		return users;

	}

	@Override
	public List<User> getUserListByName(String firstName, String lastName) {
		List<User> users = null;
		try {
			users = userDao.findUsersByName(firstName, lastName);
		}

		catch (NullPointerException e) {
			logger.error(e.getMessage(), e);
		} catch (HibernateException e) {
			logger.error(e.getMessage(), e);
		}
		return users;

	}

	@Override
	public void addFriend(User self, User user) throws UserException {
		try {
			self = userDao.read(self.getUserId());
			user = userDao.read(user.getUserId());
			if (self.getFriends().contains(user)
					&& user.getFriends().contains(self)) {
				throw new UserException(ALREADY_FRIENDS);
			}
			
			self.getFriends().add(user);
			user.getFriends().add(self);
			userDao.update(self);
			userDao.update(user);

		} catch (NullPointerException e) {
			logger.error(e.getMessage(), e);
		} catch (HibernateException e) {
			logger.error(e.getMessage(), e);
		}

	}

	@Override
	public void removeFriend(User self, User user) throws UserException {
		try {
			self = userDao.read(self.getUserId());
			user = userDao.read(user.getUserId());
			if (!self.getFriends().contains(user)
					&& !user.getFriends().contains(self)) {
				throw new UserException(ALREADY_FRIENDS);
			}
			
			self.getFriends().remove(user);
			user.getFriends().remove(self);
			userDao.update(self);
			userDao.update(user);
		} catch (NullPointerException e) {
			logger.error(e.getMessage(), e);
		} catch (HibernateException e) {
			logger.error(e.getMessage(), e);
		}
	}

	@Override
	public void enterEvent(User self, Event event) {
		try {
			self = userDao.read(self.getUserId());
			event = eventDao.read(event.getEventId());
			
			self.getEvents().add(event);
			userDao.update(self);
		} catch (NullPointerException e) {
			logger.error(e.getMessage(), e);
		} catch (HibernateException e) {
			logger.error(e.getMessage(), e);
		}
	}

	@Override
	public void leaveEvent(User self, Event event) {
		try {
			self = userDao.read(self.getUserId());
			event = eventDao.read(event.getEventId());
			
			self.getEvents().remove(event);
			userDao.update(self);

		} catch (NullPointerException e) {
			logger.error(e.getMessage(), e);
		} catch (HibernateException e) {
			logger.error(e.getMessage(), e);
		}

	}

	@Override
	public void enterForum(User self, Forum forum) {
		try {
			self = userDao.read(self.getUserId());
			forum = forumDao.read(forum.getForumId());
			
			self.getForums().add(forum);
			userDao.update(self);

		} catch (NullPointerException e) {
			logger.error(e.getMessage(), e);
		} catch (HibernateException e) {
			logger.error(e.getMessage(), e);
		}
	}

	@Override
	public void leaveForum(User self, Forum forum) throws UserException {
		try {
			self = userDao.read(self.getUserId());
			forum = forumDao.read(forum.getForumId());
			
			if (!self.getForums().contains(forum)) {
				throw new UserException("Not member of this forum");
			}
			self.getForums().remove(forum);
			userDao.update(self);
		} catch (NullPointerException e) {
			logger.error(e.getMessage(), e);
		} catch (HibernateException e) {
			logger.error(e.getMessage(), e);
		}
	}

	@Override
	public void addEducation(User self, Education education)
			throws UserException {
		try {
			education = educationDao.read(education.getEducationId());
			self = userDao.read(self.getUserId());
			if (education == null) {
				throw new NullPointerException(EDUCATION_NOT_FOUND);
			}
			if (self == null) {
				throw new NullPointerException(USER_IS_NULL);
			}
			
			if (education.getUserEducation().getUserId() == self.getUserId()) {
				throw new UserException(USER_ALREADY_HAS_THIS_EDUCATION);
			} else {
				self.getEducations().add(education);
				userDao.update(self);
			}
		} catch (NullPointerException e) {
			logger.error(e.getMessage(), e);
		} catch (HibernateException e) {
			logger.error(e.getMessage(), e);
		}
	}

	@Override
	public void deleteEducation(User self, Education education)
			throws UserException {
		try {
			education = educationDao.read(education.getEducationId());
			self = userDao.read(self.getUserId());
			if (education == null) {
				throw new NullPointerException(EDUCATION_NOT_FOUND);
			}
			if (self == null) {
				throw new NullPointerException(USER_IS_NULL);
			}
			
			if (!self.getEducations().contains(education)) {
				throw new UserException(USER_HASN_T_THIS_EDUCATION);
			}
			self.getEducations().remove(education);
			userDao.update(self);
		} catch (NullPointerException e) {
			logger.error(e.getMessage(), e);
		} catch (HibernateException e) {
			logger.error(e.getMessage(), e);
		}

	}

	@Override
	public void addJob(User self, Job job) throws UserException {
		try {
			self = userDao.read(self.getUserId());
			job = jobDao.read(job.getJobId());
			if (self == null) {
				throw new NullPointerException(USER_IS_NULL);
			}
			if (job == null) {
				throw new NullPointerException(JOB_NOT_FOUND);
			}
			
			if (self.getJobs().contains(job)) {
				throw new UserException(USER_ALREADY_HAS_THIS_JOB);
			} else {
				self.getJobs().add(job);
				userDao.update(self);
			}
		} catch (NullPointerException e) {
			logger.error(e.getMessage(), e);
		} catch (HibernateException e) {
			logger.error(e.getMessage(), e);
		}

	}

	@Override
	public void removeJob(User self, Job job) throws UserException {
		try {
			self = userDao.read(self.getUserId());
			job = jobDao.read(job.getJobId());
			
			if (!self.getJobs().contains(job)) {
				throw new UserException(USER_HASN_T_THIS_JOB);
			} else {
				self.getJobs().remove(job);
				userDao.update(self);
			}
		} catch (NullPointerException e) {
			logger.error(e.getMessage(), e);
		} catch (HibernateException e) {
			logger.error(e.getMessage(), e);
		}

	}

	@Override
	public void sendMessageToUser(User self, User user, Message message)
			throws UserException {

		try {
			self = userDao.read(self.getUserId());
			user = userDao.read(user.getUserId());
			message = messageDao.read(message.getMessageId());

			if (user == null) {
				throw new UserException("Receiver is null");
			}
			if (self == null) {
				throw new UserException("Sender is null");
			} else {
				message.setReceiver(user);
				message.setSender(self);
				messageDao.update(message);
			}

		} catch (NullPointerException e) {
			logger.error(e.getMessage(), e);
		} catch (HibernateException e) {
			logger.error(e.getMessage(), e);
		}

	}

	@Override
	public User getUserByAccount(Account account) {
		User user = null;
		try {
			account = accountDao.read(account.getAccountId());
			user = userDao.findUserByAccount(account);
		} catch (NullPointerException e) {
			logger.error(e.getMessage(), e);
		} catch (HibernateException e) {
			logger.error(e.getMessage(), e);
		}
		return user;
	}

	@Override
	public void addInterest(User self, Interest interest) throws UserException {
		try {
			self = userDao.read(self.getUserId());
			interest = interestDao.read(interest.getInterestId());
			
			if (self.getInterests().contains(interest)) {
				throw new UserException(USER_ALREADY_HAS_INTEREST);
			} else {
				self.getInterests().add(interest);
				userDao.update(self);
			}
		} catch (NullPointerException e) {
			logger.error(e.getMessage(), e);
		} catch (HibernateException e) {
			logger.error(e.getMessage(), e);
		}
	}

	@Override
	public void removeInterest(User self, Interest interest)
			throws UserException {
		try {
			self = userDao.read(self.getUserId());
			interest = interestDao.read(interest.getInterestId());
			
					
			if (!self.getInterests().contains(interest)) {
				throw new UserException(USER_HASN_T_INTEREST);
			}
			self.getInterests().remove(interest);
			userDao.update(self);

		} catch (NullPointerException e) {
			logger.error(e.getMessage(), e);
		} catch (HibernateException e) {
			logger.error(e.getMessage(), e);
		}

	}

	@Override
	public List<User> getFriends(User user) {
		List<User> users = null;
		user = userDao.read(user.getUserId());
		try {
			users = new ArrayList<User>(user.getFriends());
			for (User u : users) {
				u = userDao.read(u.getUserId());
			}
		} catch (NullPointerException e) {
			logger.error(e.getMessage(), e);
		} catch (HibernateException e) {
			logger.error(e.getMessage(), e);
		}
		return users;
	}

	@Override
	public List<User> getEventMembers(Event event) {
		List<User> users = null;
		try {
			event = eventDao.read(event.getEventId());
			users = new ArrayList<User>(event.getParticipants());
			for (User user : users) {
				user = userDao.read(user.getUserId());
			}
		} catch (NullPointerException e) {
			logger.error(e.getMessage(), e);
		} catch (HibernateException e) {
			logger.error(e.getMessage(), e);
		}
		return users;
	}

	@Override
	public List<User> getForumParticipants(Forum forum) {
		List<User> users = null;
		try {
			forum = forumDao.read(forum.getForumId());
			users = new ArrayList<User>(forum.getMembers());
			for (User user : users) {
				user = userDao.read(user.getUserId());
			}
		} catch (NullPointerException e) {
			logger.error(e.getMessage(), e);
		} catch (HibernateException e) {
			logger.error(e.getMessage(), e);
		}
		return users;
	}

	@Override
	public boolean friendOf(User self, User user) {
		try {
		self = userDao.read(self.getUserId());
		user = userDao.read(user.getUserId());
		if ( self == null || user == null){
			throw new NullPointerException();
		}
		else {
			return (self.getFriends().contains(user) && user.getFriends()
					.contains(self));
		}
		}
		catch (NullPointerException e) {
			logger.error(e.getMessage(), e);
		} catch (HibernateException e) {
			logger.error(e.getMessage(), e);
		}
		return false;
		

	}

}
